package website.seamonster.ethegg.service.background;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import website.seamonster.ethegg.conf.SystemConfig;
import website.seamonster.ethegg.dataobject.*;
import website.seamonster.ethegg.dto.BagDTO;
import website.seamonster.ethegg.enums.EggStatusEnum;
import website.seamonster.ethegg.enums.MsgTypeEnum;
import website.seamonster.ethegg.enums.TxReqStatusEnum;
import website.seamonster.ethegg.enums.TxStatusEnum;
import website.seamonster.ethegg.repository.*;
import website.seamonster.ethegg.schedule.ScheduleManager;

import java.math.BigDecimal;
import java.util.concurrent.TimeUnit;

/**
 * Created by 罗海量
 * 2018-07-22 15:18
 */
@lombok.extern.slf4j.Slf4j
@Service
public class TransactionService {
    @Autowired
    private TransactionRepository txRepository;

    @Autowired
    private EggRepository eggRepository;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private ChickenRepository chickenRepository;

    @Autowired
    private BornEggService bornEggService;

    @Autowired
    private TxReqRepository txReqRepository;

    @Autowired
    private MsgRepository msgRepository;

    /**
     * 交易成功后的回调
     * @param transactionId
     */
    @Transactional
    public void doSuccessTransaction(String transactionId){
        Transaction tx = txRepository.findOne(transactionId);
        this.doSuccessTransaction(tx);
    }

    /**
     * 交易成功后的回调
     * @param tx
     */
    @Transactional
    public void doSuccessTransaction(Transaction tx){
        if (tx != null) {
            tx.setTxStatus(TxStatusEnum.SUCCESS.getCode());

            //卖家ID
            String sellerUserId = tx.getSellId();

            //修改蛋锁定状态，蛋用户ID
            Long chickenId = this.releaseEgg(tx);

            //如果被买的蛋是某个用户的某只鸡的，且该用户当前孵化圈上限<99，该用户孵化圈上限+1，
            if (!SystemConfig.SYS_USER_ID.equals(sellerUserId) && SystemConfig.SYS_CHICKEN_ID!=chickenId) {
                User sellerUser = userRepository.findOne(sellerUserId);
                if (sellerUser.getMaxHatch() < SystemConfig.MAX_HATCH_LIMIT){
                    sellerUser.setMaxHatch(sellerUser.getMaxHatch()+1);
                    userRepository.save(sellerUser);
                }
                //如果被买的蛋是某个用户的某只鸡的，该鸡判断已生蛋数多少，如果未超过4，生一蛋
                Chicken chicken = chickenRepository.findOne(chickenId);
                bornEggService.bornEgg(chicken);
            }

            //【应该改为异步？】创建交易信息（卖蛋收益\推广收益）
            this.createMessages(tx);

            //修改交易状态（交易信息，交易请求信息）
            txRepository.save(tx);
//            this.setTxStatusFinished(tx);

            //5秒后，买回来的蛋变成鸡
            //TODO 【是否需要呢？在买蛋的时候已经判断了】注意需要先判断用户拥有的鸡的数目（包括死鸡）是否已超过该用户孵化圈上限
            //【注意】如果并行几乎可以肯定有bug，所以暂时改为串行化（之前的说明：这里一定有bug！下边的定时器会有多个线程并行，其中有个逻辑是求当前所有蛋最大seq的，肯定会重复！！）
            ScheduleManager.delayService.schedule(()->{
                try {
                    bornEggService.eggToChicken(tx.getEggId(), tx.getBuyId());
                }catch (Exception e){
                    log.error("Egg brood to Chicken error!" , e);
                }
            },SystemConfig.EGG_TO_CHICKEN_MILLSECONDS, TimeUnit.MILLISECONDS);
        }
    }

    @Transactional
    public void doFailTransaction(String transactionId, int errCode, String errDesc){
        Transaction tx = txRepository.findOne(transactionId);
        this.doFailTransaction(tx, errCode, errDesc);
    }

    @Transactional
    public void doFailTransaction(Transaction tx, int errCode, String errDesc){
        if (tx != null) {
            tx.setTxStatus(TxStatusEnum.FAIL.getCode());
            tx.setErrCode(errCode);
            tx.setErrDesc(errDesc);
            //交易请求序号
            Long txReqId = tx.getTxReqId();

            Egg eggToRelease = eggRepository.findOne(tx.getEggId());
            if (eggToRelease == null) {
                log.error("Can not find egg!! TX id：{}, TX_REQ id：{}, egg id:{}" , tx.getId(), txReqId, tx.getEggId());
            }

            eggToRelease.setEggStatus(EggStatusEnum.SALE.getCode());
            eggRepository.save(eggToRelease);

            TxReq txReq = txReqRepository.findOne(txReqId);
            txReq.setTxStatus(TxStatusEnum.FAIL.getCode());
            txReqRepository.save(txReq);
            txRepository.save(tx);

        }
    }


    /**
     * 修改蛋锁定状态，蛋用户ID, 返回该蛋所属母鸡的ID
     * @param tx
     * @return  该蛋所属母鸡的ID
     */
    private Long releaseEgg(Transaction tx) {
        //交易请求序号
        Long txReqId = tx.getTxReqId();

        Egg eggToBuy = eggRepository.findOne(tx.getEggId());
        if (eggToBuy == null) {
            log.error("Can not find egg!! TX id：{}, TX_REQ id：{}, egg id:{}" , tx.getId(), txReqId, tx.getEggId());
        }
        //蛋的母鸡ID
        Long chickenId = eggToBuy.getChickenId();
        eggToBuy.setUserId(tx.getBuyId());
        eggToBuy.setEggStatus(EggStatusEnum.BROOD.getCode());
        eggRepository.save(eggToBuy);
        return chickenId;
    }

    private void setTxStatusFinished(Transaction tx) {
        //交易请求序号
        Long txReqId = tx.getTxReqId();

        txRepository.save(tx);
        TxReq txReq = txReqRepository.findOne(txReqId);
        txReq.setTxStatus(TxStatusEnum.SUCCESS.getCode());
        txReqRepository.save(txReq);
    }



    /**
     * 获取下一条待处理的交易
     * @return
     */
    public Transaction getNextTransaction(){
        Transaction tx = txRepository.findFirstByTxStatusOrderByTxReqIdAsc(TxReqStatusEnum.WAIT.getCode());
        return tx;
    }


    private void createMessages(Transaction tx){
        String sellUserId = tx.getSellId();
        String prUserId = tx.getPrUserId();
        BigDecimal sellIncome = tx.getSellIncome();
        BigDecimal prIncome = tx.getPrIncome();

        //首先发送推广码收益消息
        if (prUserId != null) {
            Msg msgPr = new Msg();
            msgPr.setMsgType(MsgTypeEnum.PRINCOME.getCode());
            msgPr.setUserId(prUserId);
            msgPr.setIncome(prIncome);
            msgRepository.save(msgPr);
        }

        if (SystemConfig.SYS_USER_ID.equals(sellUserId)){
            //卖家是系统，不用发收益信息
            return;
        } else {
            Msg msg = new Msg();
            msg.setMsgType(MsgTypeEnum.SELLSUCCESS.getCode());
            msg.setUserId(sellUserId);
            msg.setReadStatus(false);
            msg.setIncome(sellIncome);
            msgRepository.save(msg);
        }
    }

    public BagDTO getIncomeInfo(String userId){
        BagDTO bagDTO = new BagDTO();
        bagDTO.setSellIncome(txRepository.sumSellIncome(userId, TxStatusEnum.SUCCESS.getCode()));
        bagDTO.setPrIncome(txRepository.sumPrIncome(userId, TxStatusEnum.SUCCESS.getCode()));
        if (bagDTO.getSellIncome() == null){
            bagDTO.setSellIncome(BigDecimal.ZERO);
        }
        if (bagDTO.getPrIncome() == null){
            bagDTO.setPrIncome(BigDecimal.ZERO);
        }
        return bagDTO;
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void createFailTx(TxReq req, Integer errCode, String errMsg){
        Transaction failTx = new Transaction();
        failTx.setErrCode(errCode);
        failTx.setErrDesc(errMsg);
        failTx.setTxStatus(TxStatusEnum.FAIL.getCode());
        failTx.setTxReqId(req.getId());
        Transaction t = txRepository.save(failTx);
    }
}
